package tirateima.gui.arquivos;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.io.Writer;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.smartcardio.ATR;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.plaf.TextUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
import javax.swing.text.Highlighter;
import javax.swing.text.Highlighter.HighlightPainter;
import javax.swing.text.StyleContext.NamedStyle;
import javax.swing.text.JTextComponent;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;

import tirateima.IEstado;


public class VarFile extends AbstractArquivo implements IEstado {
	
	public class EstadoVarFile{
		public StringBuffer texto;
		
		public int posicaoPonteiro;
		
		public File file;

		public String titulo;
	}
	
	public class FilePointerHighLight implements Highlighter.HighlightPainter {
		Color cor = Color.RED;
		
		
		public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) {
			// TODO Auto-generated method stub
			TextUI mapper = c.getUI();
			Rectangle p0 = null;
			
			try {
				p0 = mapper.modelToView(c, offs0);
			} catch (BadLocationException e) {
				e.printStackTrace();
			}
			
			/* Desenha os marcadores */
			int altura = p0.height/4;
			int largura = (int) (altura * 0.85);
			int xpoints[] = new int[3];
			int ypoints[] = new int[3];
			
			/* Primeiro */
			
			/* Esquerdo. */
			xpoints[0] = p0.x;
			ypoints[0] = p0.y + p0.height;
			
			/* Superior. */
			xpoints[1] = p0.x;
			ypoints[1] = p0.y + p0.height - altura;
			
			/* Direito. */
			xpoints[2] = p0.x + largura;
			ypoints[2] = p0.y + p0.height;
			
			g.setColor(Color.RED);
			g.drawPolygon(new Polygon(xpoints, ypoints, 3));
			g.fillPolygon(new Polygon(xpoints, ypoints, 3));
		}
		
		
	}
	
	
	
	private JTextPane pPrincipal;
	private int posicaoPonteiro = 0;
	
	
	private StringBuffer texto = null;
	
	private static final long serialVersionUID = 1L;
	
	/**
	 * Cria uma nova variável do tipo arquivo texto de Pascal.
	 * 
	 * @param nome Nome desta variável
	 */
	public VarFile(String nome){
		super(nome);
		inicializar();
	}

	public void close() throws IOException {
		DefaultHighlighter dh = (DefaultHighlighter) pPrincipal.getHighlighter();
		dh.removeAllHighlights();
		
		pPrincipal.setText("");
		posicaoPonteiro = 0;
		titulo = "";
		borda.setTitulo(nome);
		texto = null;
	}

	public boolean eof() {
		return false;
	}

	public Color getCorTitulo() {
		return Color.green;
	}


	private void inicializar(){
		setLayout(new GridBagLayout());
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.anchor = GridBagConstraints.CENTER;
		gbc.fill = GridBagConstraints.BOTH;
		gbc.weightx = gbc.weighty = 1.0;
		
		add(new JScrollPane(getPPrincipal()), gbc);
	}
	
	private JTextPane getPPrincipal(){
		if(pPrincipal == null){
			pPrincipal = new JTextPane();
			pPrincipal.setFont(pPrincipal.getFont().deriveFont(30.0f));
			//pPrincipal.setEditable(false);
			criarEstilos();
		}
		return pPrincipal;
	}
	
	
	private void criarEstilos() {
		StyledDocument doc = pPrincipal.getStyledDocument();
		
		StyleContext sc = StyleContext.getDefaultStyleContext();
		Font f = pPrincipal.getFont();
		
		/* Estilo para texto qualquer...*/
		Style normal = sc.new NamedStyle();
		normal.addAttributes(StyleContext.getDefaultStyleContext().
	        	getStyle(StyleContext.DEFAULT_STYLE).copyAttributes());
		//StyleConstants.setFontSize(normal, 20);
		StyleConstants.setFontFamily(normal, f.getFamily());
		StyleConstants.setBold(normal, true);
		doc.addStyle("normal", normal);
		
		/* Estilo para caractere de fim de linha...*/
		Style s = sc.new NamedStyle();
		s.addAttributes(normal.copyAttributes());
		StyleConstants.setForeground(s, Color.DARK_GRAY);
		StyleConstants.setBold(s, false);
		doc.addStyle("eol", s);
		
		/* Estilo para caractere de fim de arquivo...*/
		s = sc.new NamedStyle();
		s.addAttributes(normal.copyAttributes());
		StyleConstants.setForeground(s, Color.RED);
		StyleConstants.setBold(s, false);
		doc.addStyle("eof", s);
	}
	
	private static String readFileAsString(File file) throws java.io.IOException{
	    byte[] buffer = new byte[(int) file.length()];
	    BufferedInputStream f = null;
	    try {
	        f = new BufferedInputStream(new FileInputStream(file.getPath()));
	        f.read(buffer);
	    } 
	    catch (Exception e) {
			e.printStackTrace();
		}
	    finally {
	        if (f != null) try { f.close(); } catch (IOException ignored) { }
	    }
	    return new String(buffer);
	}
	
	private void atualizarHighlights(int p1, int p2) throws BadLocationException {
		DefaultHighlighter dh = (DefaultHighlighter) pPrincipal.getHighlighter();
		dh.removeAllHighlights();
		//dh.addHighlight(p1, p2, DefaultHighlighter.DefaultPainter);
		dh.addHighlight(p1, p2, new FilePointerHighLight());
		pPrincipal.repaint();
	}
	
	/*private void atualizarHighlightsEol(int posicaoRealPonteiro) throws BadLocationException {
		DefaultHighlighter dh = (DefaultHighlighter) pPrincipal.getHighlighter();
		dh.addHighlight(posicaoRealPonteiro, posicaoRealPonteiro + 2, DefaultHighlighter.DefaultPainter);
		//dh.addHighlight(posicaoRealPonteiro, posicaoRealPonteiro + 2, new FilePointerHighLight());
	}*/
	
	
	public void atualizaConteudo()
	{
		char cbuf[], c;
		
		
		if (titulo == null || texto == null)
			return;
		
		pPrincipal.setText("");
		
		StringReader strreader = new StringReader(texto.toString());
		BufferedReader reader = new BufferedReader(strreader);
		StyledDocument doc = pPrincipal.getStyledDocument();
		
		cbuf = new char[this.texto.length()];
		
		int posicaoHl1 = 0, posicaoHl2 = 0;
		
		try {
			reader.read(cbuf);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		
		try {
			for (int i = 0; i < cbuf.length; i++ ) {  
				c = cbuf[i];
				
				if (c == '\n')
					doc.insertString(doc.getLength(), "\\n\n", pPrincipal.getStyle("eol"));	
				else
					doc.insertString(doc.getLength(), ""+c, pPrincipal.getStyle("normal"));	
				
				if (posicaoPonteiro == i)
				{
					if (c == '\n')
					{
						posicaoHl1 = doc.getLength() - 3;
						posicaoHl2 = posicaoHl1 + 2;
					}
					else
					{
						posicaoHl1 = doc.getLength()-1;
						posicaoHl2 = posicaoHl1 + 1;
					}
					
				}
				
			}			
			

			if (posicaoPonteiro == cbuf.length)
			{
				posicaoHl1 = doc.getLength();
				doc.insertString(doc.getLength(), "eof\n",pPrincipal.getStyle("eof"));
				atualizarHighlights(posicaoHl1, posicaoHl1 + 3);
			}
			else
			{
				atualizarHighlights(posicaoHl1, posicaoHl2);
				doc.insertString(doc.getLength(), "eof\n",pPrincipal.getStyle("eof"));
			}
			
		} catch (BadLocationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//System.out.println("  posicao pt: " + posicaoPonteiro);
		
	}
	
	
	@Override
	public void open(String nome_arq) throws Exception {
		file = nome_arq == null ? null : new File(nome_arq);
		titulo = nome + (file == null ? "" : " : '" + file.getName() + "'");
		fileNameAux = new String(file.getName());
		borda.setTitulo(titulo);
		
		if (file != null && file.exists())
		{
			this.texto = new StringBuffer(readFileAsString(file));
		}
		else
		{
			this.texto = new StringBuffer();
		}
		
		//pPrincipal.setText(this.texto.toString());
		atualizaConteudo();
		pPrincipal.repaint();
	}
	
	public void atualizaPosicaoPonteiro(int posicao, String seekset) {
		int prelativa = 0;
		
		//System.out.println(seekset+posicao);
		
		if(seekset.equals("[SEEK_SET]")){
			prelativa=0;
		}
		else if (seekset.equals("[SEEK_CUR]")){
			prelativa  = this.posicaoPonteiro;
		}
		else if (seekset.equals("[SEEK_END]")){
			prelativa = this.texto.length();
		}
		
		posicaoPonteiro = prelativa + posicao;
		
		if (posicaoPonteiro < 0)
			posicaoPonteiro = 0;
		else if (posicaoPonteiro > this.texto.length())
			posicaoPonteiro = this.texto.length();
		
		System.out.println(posicaoPonteiro);
		
		atualizaConteudo();
		pPrincipal.repaint();
	}
	
		
	//IEstado
	public Object getEstado() {
		EstadoVarFile e = new EstadoVarFile();
	
		e.posicaoPonteiro = posicaoPonteiro;
		e.file   = file == null ? null : new File(file.getName());
		e.texto  = texto == null ? null : new StringBuffer(texto.toString());
		e.titulo = titulo;
		
		return e;
	}
	
	public void setEstado(Object estado) {
		if(estado == null) {
			texto = null;
			file = null;
			posicaoPonteiro = 0;
			titulo = null;
			borda.setTitulo(nome);
			pPrincipal.setText("");
		}
		else {
			EstadoVarFile e = (EstadoVarFile) estado;
			file = e.file;
			posicaoPonteiro = e.posicaoPonteiro;
			texto = e.texto;
			titulo = e.titulo;
			
			atualizaConteudo();

		}
		validate();
		repaint();
	}
	
	

	@Override
	public void reset() throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void rewrite() throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Object read() throws IOException {
		// TODO Auto-generated method stub
		return null;
	}
	
	private boolean isSeparador(char c)
	{
		if ( c ==  ' ' || c == '\n') 
			return true;
		else
			return false;
	}
	
	public char getNextChar() {
		char c = 0;
		int nbytes =0;
		
		char cseq[] = this.texto.substring(posicaoPonteiro).toCharArray();
		
		if (cseq.length > 1)
		{
			c = cseq[0];
			nbytes = 1;
		}
		posicaoPonteiro += nbytes;	
		return c;
	}
	
	public String getNextToken() {
		String token = "";
		int nbytes = 0;
		int i=0;
		
		//System.out.println("   Operacao get Token:");
		
		char cseq[] = this.texto.substring(posicaoPonteiro).toCharArray();
		
		for (i=0;i<cseq.length && (isSeparador(cseq[i])) ; i++);

		//System.out.println("    Nbytes: " + i);
		
		for (;i<cseq.length && (!isSeparador(cseq[i])) ; i++)
		{

			token = token+cseq[i];
		}
		
		nbytes = i;

		//System.out.println("    Nbytes: " + nbytes);
		posicaoPonteiro += nbytes;	
		return token;
	}

	public void printStr(String buf) {
		//this.texto.insert(posicaoPonteiro, buf);
		this.texto.replace(posicaoPonteiro, posicaoPonteiro+1, buf);
		posicaoPonteiro+=buf.length();
	}
	


	
	
}
